#include <iostream>
#include <typeinfo>
#include <algorithm>
#include <assert.h>
#include <string>
#include <unistd.h>
#include <any>

class Any
{
private:
    class holder       //父类，用来被继承的
    {
    public:
        virtual ~holder() {}
        virtual const std::type_info& type() = 0 ;     
        virtual holder* clone() = 0 ;           
    };

    //子类才是用来保存数据的
    template<class T>
    class placeholder : public holder      //子类继承父类
    {
    public:
        placeholder(const T& val) : _val(val) {}  //内置类型不做处理，自定义类型T会调用它的拷贝构造
        // 获取子类对象的数据类型
        virtual const std::type_info& type() { return typeid(T); } 
        // 针对当前子类对象自身，克隆一个新的子类对象
        virtual holder* clone() { return new placeholder(_val); }
    public:
        T _val;
    };

    holder* _content;

public:
    Any() :_content(nullptr) {}
    template<class T>
    Any(const T& val) : _content(new placeholder<T>(val)) {}               //根据数据类型构造一个Any对象
    Any(const Any& other) : _content(other._content == nullptr ? nullptr : other._content->clone()) {}     //拷贝构造
    //这里的拷贝构造不能直接复制一个other地址，而是要复制other对象内的父类指针指向的子类对象(placeholder)的地址
    ~Any() {delete _content;}

    Any& swap(Any& other)  //加了const后，other的_content是const修饰的，而原本的_content是可修改的
                                //这样就会出现权限放大的情况
    {
        std::swap(_content, other._content); 
        return *this;    //返回对象本身是为了支持连续swap操作/赋值操作
    }

    template<class T> 
    T* get()                       //返回子类对象保存的数据的指针
    {
        //我当前保存的数据类型与想要返回的数据类型不匹配
        assert(typeid(T) == _content->type()) ; //条件成立继续，不成立报错

        return &(((placeholder<T>*)_content)->_val);
        // _content是一个父类指针，先转化成子类.
    }

    template<class T>
    Any& operator=(const T& val)    //赋值运算符重载
    {
        Any(val).swap(*this); //为val构造一个临时Any通用容器对象，然后与自身Any容器的_content指针交换
        //交换后不会再关心自身容器的_content了，因为交换之后，临时对象出了作用域会调用析构函数进行销毁
        
        //此时保留的就是val构造出来的_content;
        return *this;  // 为了支持连续赋值
    }

    Any& operator=(const Any& other)
    {
        Any(other).swap(*this);
        //调用拷贝构造为other对象构造一个新的临时Any对象，用该对象与我自身的_content指针交换，交换后
        //原来_content指针保存的数据就跟随临时对象调用析构销毁了

        //这样既不影响到other，又能销毁原指针指向的数据。
        return *this;   //支持连续的赋值重载
    }

};

class Test
{
public:
    Test()
    {
        std::cout << "构造" << std::endl;
    }

    Test(const Test& t)
    {
        std::cout << "拷贝构造" << std::endl;
    }

    ~Test()
    {
        std::cout << "析构" << std::endl;
    }
};

// int main()
// {
//     //Any a = 10; //构造+拷贝构造，编译器会优化成构造

//     Any a; //先构造 ，无参构造是默认构造函数，不需要我们写而自动生成的
//     {
//         Test t;
//         a = t;
//     }
//     //打印两次析构是因为在a = t实现时，用 T& val类型拷贝构造了Any临时对象。
//     //赋值重载结束后,_content所管理的临时对象T类会释放，这时候T是自定义类型，自定义类型会自动调用析构释放

//     // a = 10; //再赋值重载
//     // int *pa = a.get<int>();
//     // std:: cout << *pa << std::endl;

//     // a = std::string("hello world");

//     // std::string* ps = a.get<std::string>();

//     // std::cout << *ps << std::endl;
//     return 0;
// }

//使用官方库的any，编译的时候要 g++ -o any any.cpp -std=c++17
// int main()
// {
//     std::any a;
//     a = 10;
//     int *pa = std::any_cast<int>(&a); //相当于我们自己实现的get函数
//     std::cout << *pa << std::endl;
    
//     a = std::string("hello world");
//     std::string* ps = std::any_cast<std::string>(&a);
//     std::cout << *ps << std::endl;

//     return 0;
// }   